/*
 * Tranquil Java Integrated Development Environment
 *
 * The GNU General Public License Version 3
 *
 * Copyright (C) 2021 Autumn Lamonte
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Autumn Lamonte [AutumnWalksTheLake@gmail.com] ⚧ Trans Liberation Now
 * @version 1
 */
package tjide.project;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import gjexer.TWindow;

import tjide.build.CompileListener;

/**
 * A Target is something that must be compiled before it can be used in an
 * application.
 */
public abstract class Target {

    // ------------------------------------------------------------------------
    // Variables --------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * The listeners monitoring compile().
     */
    protected List<CompileListener> compileListeners = new ArrayList<CompileListener>();

    /**
     * The name of the target as seen in the project window.  This doesn't
     * have to match the build filename.  Usually it will be the file part of
     * the build filename's path, e.g. "HelloWorld.class".
     */
    protected String name;

    /**
     * The name of the generated file, relative to the Project's build output
     * directory.  This is a relative path and filename,
     * e.g. "com/helloworld/HelloWorld.class"
     */
    protected String buildFilename;

    /**
     * Line count, filled in by compile().
     */
    protected int lineCount = -1;

    /**
     * Error count, filled in by compile().
     */
    protected int errorCount = -1;

    /**
     * Warning count, filled in by compile().
     */
    protected int warningCount = -1;

    /**
     * The UI window associated with this target.
     */
    protected TWindow window;

    // ------------------------------------------------------------------------
    // Constructors -----------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Protected constructor for subclasses.
     *
     * @param name the target's name to show in the UI
     * @param buildFilename the name of the generated file, relative to the
     * project's build directory
     */
    protected Target(final String name, final String buildFilename) {
        this.name               = name;
        this.buildFilename      = buildFilename;
    }

    // ------------------------------------------------------------------------
    // Target -----------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Get the target window.
     *
     * @return the target's associated window, or null if it is not visible
     */
    public final TWindow getWindow() {
        return window;
    }

    /**
     * Set the target window.
     *
     * @param window the target's associated window
     */
    public final void setWindow(final TWindow window) {
        this.window = window;
    }

    /**
     * Add a compile listener to this target.
     *
     * @param listener the listener
     */
    public final void addCompileListener(final CompileListener listener) {
        compileListeners.add(listener);
    }

    /**
     * Set the compile listeners of this target to one listener.
     *
     * @param listener the listener
     */
    public final void setCompileListener(final CompileListener listener) {
        compileListeners = new ArrayList<CompileListener>();
        compileListeners.add(listener);
    }

    /**
     * Get the target's name in the UI.
     *
     * @return the target UI name
     */
    public final String getName() {
        return name;
    }

    /**
     * Set the target's name in the UI.
     *
     * @param name the new target UI name
     */
    public final void setName(final String name) {
        this.name = name;
    }

    /**
     * Get the generated filename of the target, relative to the Project's
     * build output directory.
     *
     * @return the filename
     */
    public final String getBuildFilename() {
        return buildFilename;
    }

    /**
     * Set the generated filename of the target, relative to the Project's
     * build output directory.
     *
     * @param buildFilename the filename
     */
    public final void setBuildFilename(final String buildFilename) {
        this.buildFilename = buildFilename;
    }

    /**
     * Check if target is stale.
     *
     * @param time the time to compare the target's buildFilename to.  If the
     * target was built on or after this time, it is not stale.
     * @param buildDirName the project's build output directory
     * @return true if the target needs to be rebuilt
     */
    public boolean isStale(final long time, final String buildDirName) {
        /*
        System.err.println("isStale() checking " +
            (new File(buildDirName, buildFilename)));
        */

        File file = new File(buildDirName, buildFilename);
        if (!file.exists()) {
            return true;
        }
        if (!file.isFile()) {
            // Say that the target is stale.  Rebuilding it will generate an
            // error to expose to the user.
            return true;
        }

        if (file.lastModified() >= time) {
            // System.err.println("   " + file + " is newer, NOT stale");
            // Target is newer than time, we are not stale.
            return false;
        } else {
            // System.err.println("   " + file + " is older, STALE");
            // Target is older than time, we are stale.
            return true;
        }
    }

    /**
     * Check if target is stale.
     *
     * @param sourceDirName the project's source directory
     * @param buildDirName the project's build output directory
     * @return true if the target needs to be rebuilt
     */
    public abstract boolean isStale(final String sourceDirName,
        final String buildDirName);

    /**
     * Compile the target.  Subclasses must provide an implementation.
     *
     * @param project the project metadata
     */
    public abstract void compile(final Project project);

}
